package com.xzj.common.secure.advice;

import com.xzj.common.secure.annotation.XzjEncrypt;
import com.xzj.common.secure.util.SecureAdviceUtil;
import com.xzj.common.secure.util.XzjSecureUtil;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @program: xzj-common
 * @ClassName: EncryptResponseAdvice
 * @description: 接口返回参加密
 * @author: XiaZunJun
 * @create: 2024-08-05 11:16
 */
@RestControllerAdvice
@Order(1)
public class EncryptResponseAdvice implements ResponseBodyAdvice<Object> {

    /**
     * 判断当前的HttpMessageConverter是否支持处理被@Encrypt注解的方法返回值
     *
     * @param returnType    包含返回值信息的MethodParameter对象，用于分析返回值是否带有@Encrypt注解
     * @param converterType 当前使用的HttpMessageConverter类型，用于确定支持的媒体类型
     * @return 如果returnType带有@Encrypt注解并且converterType是合适的HttpMessageConverter类型，则返回true，否则返回false
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.hasMethodAnnotation(XzjEncrypt.class);
    }

    /**
     * 在响应返回给客户端之前对响应体进行处理，这个方法允许你修改、替换或者完全自定义响应体
     *
     * @param body                  方法执行后返回的对象，代表了原始的响应体，在这个方法中你可以对它进行修改或者替换
     * @param returnType            包含了返回值类型信息的 MethodParameter 对象
     * @param selectedContentType   处理请求时选择的媒体类型，比如 application/json、application/xml 等
     * @param selectedConverterType 处理请求时选择的消息转换器类型，例如 Jackson 或者 JAXB 等
     * @param request               当前的 ServerHttpRequest，包含了所有关于请求的信息
     * @param response              响应对象，允许你设置响应头和修改响应体
     * @return 返回要作为响应体的数据对象，如果你不想修改响应体，可以直接返回原本的 body；如果你想替换响应体，返回新的对象
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        Method method = returnType.getMethod();
        List<String> headList = request.getHeaders().get("IS_DECRYPT");
        if(null == headList || "true".equals(headList.get(0))){
            Class<?> resultType = method.getReturnType();
            if(resultType.equals(String.class)){
                body = XzjSecureUtil.aesEncrypt(body.toString());
            }else{
                Field[] declaredFields = resultType.getDeclaredFields();
                for (Field field: declaredFields){
                    SecureAdviceUtil.judgeEncryptField(field, body);
                }
            }
        }
        return body;
    }
}
